/*
 * Copyright 2009-2009 Tanesha Project. All rights reserved.
 * 
 * Redistribution and use in source and binary forms, with or without modification, 
 * are permitted provided that the following conditions are met:
 * 
 *    1. Redistributions of source code must retain the above copyright notice, 
 *    	 this list of conditions and the following disclaimer.
 *    2. Redistributions in binary form must reproduce the above copyright notice,
 *    	 this list of conditions and the following disclaimer in the documentation 
 *    	 and/or other materials provided with the distribution.
 * 
 * THIS SOFTWARE IS PROVIDED BY THE FREEBSD PROJECT ``AS IS'' AND ANY EXPRESS OR 
 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF 
 * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT 
 * SHALL THE FREEBSD PROJECT OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, 
 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 
 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, 
 * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF 
 * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE 
 * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
 *  OF THE POSSIBILITY OF SUCH DAMAGE.
 * 
 * The views and conclusions contained in the software and documentation are those 
 * of the authors and should not be interpreted as representing official policies, 
 * either expressed or implied, of the Tanesha Project.
 */
package com.google.api.chart;

import java.awt.Dimension;
import java.util.ArrayList;
import java.util.List;

import com.google.api.chart.ChartMaker.DoublesDataSeriesMaker;
import com.google.api.chart.encoding.DataEncoder;
import com.google.api.chart.encoding.TextDataEncoder;
import com.google.api.chart.features.AxisAndLabelFeature;
import com.google.api.chart.features.BarFeature;
import com.google.api.chart.features.ColorFeature;
import com.google.api.chart.features.FillAreaFeature;
import com.google.api.chart.features.FillFeature;
import com.google.api.chart.features.FinancialMarkerFeature;
import com.google.api.chart.features.GoogleOMeterAndPieLabelsFeature;
import com.google.api.chart.features.GridLineFeature;
import com.google.api.chart.features.LegendFeature;
import com.google.api.chart.features.LineStylesFeature;
import com.google.api.chart.features.MapFeature;
import com.google.api.chart.features.RangeMarkerFeature;
import com.google.api.chart.features.ScalingFeature;
import com.google.api.chart.features.ShapeMarkerFeature;
import com.google.api.chart.features.TitleFeature;

/**
 * SimpleChartMaker is the alternative main class for generating charts.
 * <p>
 * The difference between ChartMaker and SimpleChartMaker, is that SimpleChartMaker
 * exposes all the chart functions inside SimpleChartMaker. It is then up to the
 * user to specify a meaningful chart. It gives a simpler API, but slightly easier
 * to construct charts that are not useful.  An {@link IllegalArgumentException} will
 * be thrown if an illegal chart option is constructed
 * </p>
 * 
 * @see ChartMaker
 * @author sorenad
 */
public class SimpleChartMaker implements AxisAndLabelFeature<SimpleChartMaker>, BarFeature<SimpleChartMaker>, ColorFeature<SimpleChartMaker>, FillAreaFeature<SimpleChartMaker>, FinancialMarkerFeature<SimpleChartMaker>, GoogleOMeterAndPieLabelsFeature<SimpleChartMaker>, GridLineFeature<SimpleChartMaker>, LegendFeature<SimpleChartMaker>, LineStylesFeature<SimpleChartMaker>, RangeMarkerFeature<SimpleChartMaker>, ScalingFeature<SimpleChartMaker>, ShapeMarkerFeature<SimpleChartMaker>, TitleFeature<SimpleChartMaker>, FillFeature<SimpleChartMaker>, MapFeature<SimpleChartMaker> {
	
	private ChartTypeMaker type = ChartMaker.bar();
	private Dimension size = new Dimension(250, 150);
	private List<DataSeriesMaker> dataSeries = new ArrayList<DataSeriesMaker>();
	private DataEncoder dataEncoder = new TextDataEncoder();
	
	public SimpleChartMaker(ChartTypeMaker type) {
		this.type = type;
	}

	public byte[] getImageData() throws Exception {
		return URLHelper.retrieveURL(getURL());
	}
	
	public String getURL() {
		return URLHelper.buildURL(type, size, dataEncoder, dataSeries);
	}
	
	public SimpleChartMaker data(double[][] data) {
		for (int i = 0; i < data.length; i++)
			dataSeries.add(new DoublesDataSeriesMaker(data[i]));
		return this;
	}

	public SimpleChartMaker data(DataSeriesMaker... data) {
		for (int i = 0; i < data.length; i++)
			dataSeries.add(data[i]);
		return this;
	}
	
	public SimpleChartMaker size(Dimension size) {
		this.size = size;
		return this;
	}
	
	public SimpleChartMaker dataEncoder(DataEncoder dataEncoder) {
		this.dataEncoder  = dataEncoder;
		return this;
	}

	@SuppressWarnings("unchecked")
	public static <T> T tryFunction(Class<T> clazz, Object obj) {
		if (clazz.isAssignableFrom(obj.getClass()))
			return (T) obj;
		else
			throw new IllegalArgumentException("Current chart does not support this feature, use type(ChartTypeMaker) to specify type.");
	}
	
	@Override
	public SimpleChartMaker axes(AxisMaker... axises) {
		tryFunction(AxisAndLabelFeature.class, type).axes(axises);
		return this;
	}

	@Override
	public SimpleChartMaker dataLabels(DataLabelMaker... dataLabels) {
		tryFunction(AxisAndLabelFeature.class, type).dataLabels(dataLabels);
		return this;
	}

	@Override
	public SimpleChartMaker autosize(double barSpacing, double groupSpacing) {
		tryFunction(BarChartMaker.class, type).autosize(barSpacing, groupSpacing);
		return this;
	}
	
	@Override
	public SimpleChartMaker autosize() {
		tryFunction(BarChartMaker.class, type).autosize();
		return this;
	}

	@Override
	public SimpleChartMaker fixed(double width, double barSpacing, double groupSpacing) {
		tryFunction(BarChartMaker.class, type).fixed(width, barSpacing, groupSpacing);
		return this;
	}

	@Override
	public SimpleChartMaker relative(double barSpacing, double groupSpacing) {
		tryFunction(BarChartMaker.class, type).relative(barSpacing, groupSpacing);
		return this;
	}

	@Override
	public SimpleChartMaker zerolines(double... percents) {
		tryFunction(BarChartMaker.class, type).zerolines(percents);
		return this;
	}

	@Override
	public SimpleChartMaker colors(ColorMaker... colors) {
		tryFunction(ColorFeature.class, type).colors(colors);
		return this;
	}

	@Override
	public SimpleChartMaker fillAreas(FillAreaMaker... fills) {
		tryFunction(FillAreaFeature.class, type).fillAreas(fills);
		return this;
	}

	@Override
	public SimpleChartMaker label(String... labels) {
		tryFunction(GoogleOMeterAndPieLabelsFeature.class, type).label(labels);
		return this;
	}

	@Override
	public SimpleChartMaker legend(String... legends) {
		tryFunction(LegendFeature.class, type).legend(legends);
		return this;
	}

	@Override
	public SimpleChartMaker legend(ChartLegendMaker legend) {
		tryFunction(LegendFeature.class, type).legend(legend);
		return this;
	}

	@Override
	public SimpleChartMaker linestyles(LineStyleMaker... linestyles) {
		tryFunction(LineStylesFeature.class, type).linestyles(linestyles);
		return this;
	}

	@Override
	public SimpleChartMaker scaling(ScalingMaker... scaling) {
		tryFunction(ScalingFeature.class, type).scaling(scaling);
		return this;
	}

	@Override
	public SimpleChartMaker title(String... title) {
		tryFunction(TitleFeature.class, type).title(title);
		return this;
	}

	@Override
	public SimpleChartMaker title(ColorMaker color, int textSize, String... title) {
		tryFunction(TitleFeature.class, type).title(color, textSize, title);
		return this;
	}
	
	@Override
	public SimpleChartMaker gridlines(GridLineMaker gridlines) {
		tryFunction(GridLineFeature.class, type).gridlines(gridlines);
		return this;
	}
	
	@Override
	public SimpleChartMaker shapes(ShapeMarkerMaker... shapes) {
		tryFunction(ShapeMarkerFeature.class, type).shapes(shapes);
		return this;
	}
	
	@Override
	public SimpleChartMaker ranges(RangeMarkerMaker... ranges) {
		tryFunction(RangeMarkerFeature.class, type).ranges(ranges);
		return this;
	}
	
	@Override
	public SimpleChartMaker financial(FinancialMarkerMaker... financials) {
		tryFunction(FinancialMarkerFeature.class, type).financial(financials);
		return this;
	}
	
	@Override
	public SimpleChartMaker margins(MarginMaker margins) {
		tryFunction(TitleFeature.class, type).margins(margins);
		return this;
	}
	
	@Override
	public SimpleChartMaker fills(FillMaker... fills) {
		tryFunction(FillFeature.class, type).fills(fills);
		return this;
	}
	
	@Override
	public SimpleChartMaker locations(LocationMaker... locations) {
		tryFunction(MapFeature.class, type).locations(locations);
		return this;
	}
}
